/*
 * Copyright 2009 BioTeam Inc
 * 
 * Licensed under License GNU LESSER GENERAL PUBLIC LICENSE version 3.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.gnu.org/copyleft/lesser.html
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package net.bioteam.appweb.model;

import junit.framework.Assert;
import junit.framework.TestCase;

import net.bioteam.appweb.Config;
import net.bioteam.appweb.TestConfig;
import net.bioteam.appweb.acd.AcdToProgram;
import net.bioteam.appweb.acd.AcdToProgramTest;
import net.sf.ehcache.CacheManager;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;

import java.util.Arrays;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

public class ProgramBuilderTest extends TestCase
{

	public ProgramBuilderTest()
	{
		super();
	}

	public ProgramBuilderTest(String test)
	{
		super(test);
	}

	public static void main(String args[])
	{
		ProgramBuilderTest test = new ProgramBuilderTest("testGroupInheritance");
		junit.textui.TestRunner.run(test);
	}

	public void setUp() throws Exception
	{
		TestConfig.init();
		// Beanshell
		// ProgramModifier modifier = new ExampleProgramModifier();
		ProgramModifier modifier = new BeanshellProgramModifier();
		ProgramBuilder.modifiers.add(modifier);
	}

	public void tearDown() throws Exception
	{
		TestConfig.shutdown();
	}

	public void testGroupInheritance() throws Exception
	{
		ProgramBuilder.cache.remove("example");
		ProgramBuilder.cache.remove("example1");

		Program program = ProgramBuilder.getProgram("example");

		
		Assert.assertEquals(new Integer(1), program.getParameter("first").getGroup());
		Assert.assertEquals(new Integer(-1), program.getParameter("second").getGroup());

		// inherited from enclosing paragraph
		Assert.assertEquals(new Integer(5), program.getParameter("seq").getGroup());
		Assert.assertEquals(new Integer(6), program.getParameter("infile").getGroup());
		Assert.assertEquals(new Integer(4), program.getParameter("str").getGroup());
		Assert.assertEquals(new Integer(5), program.getParameter("aint").getGroup());
		Assert.assertEquals(new Integer(5), program.getParameter("afloat").getGroup());
		Assert.assertEquals(new Integer(5), program.getParameter("aswitch").getGroup());
		Assert.assertEquals(new Integer(5), program.getParameter("bswitch").getGroup());
		Assert.assertEquals(new Integer(10), program.getParameter("a_selection").getGroup());
		Assert.assertEquals(new Integer(11), program.getParameter("multi_selection").getGroup());

		// inherited from top paragraph
		Assert.assertEquals(new Integer(5), program.getParameter("seq1").getGroup());
	}

	/**
	 * Make sure we have default value correctly.
	 */
	public void testOuputDefaultValue()
	{
		try
		{
			ProgramBuilder.cache.remove("example1");
			Program cmd = ProgramBuilder.getProgram("example1");

			// out file default value
			Parameter param = cmd.getParameter("p_outfile_simple");
			Assert.assertEquals("outfile", param.getDeaultValue());

			// switch default value
			param = cmd.getParameter("p_switch1");
			Assert.assertEquals("0", param.getDeaultValue());
			param = cmd.getParameter("p_switch2");
			Assert.assertEquals("0", param.getDeaultValue());
			param = cmd.getParameter("p_switch3");
			Assert.assertEquals("1", param.getDeaultValue());

			// excl value
			param = cmd.getParameter("p_excl");
			Assert.assertEquals("50.0", param.getDeaultValue());
			param = cmd.getParameter("p_excl1");
			Assert.assertEquals("70.0", param.getDeaultValue());

			// list default value.
			param = cmd.getParameter("p_list3");
			List<String> def = param.getDefaultAsList();
			Assert.assertEquals(2, def.size());
			Assert.assertEquals(def.get(0), "50.0");
			param = cmd.getParameter("p_list4");
			def = param.getDefaultAsList();
			Assert.assertEquals(2, def.size());
			Assert.assertEquals(def.get(0), "50.0");

			param = cmd.getParameter("p_integer");
			Assert.assertEquals(1, Integer.parseInt(param.getDeaultValue()));
			param = cmd.getParameter("p_integer2");
			Assert.assertEquals(5, Integer.parseInt(param.getDeaultValue()));

			param = cmd.getParameter("p_float2");
			Assert.assertEquals(5.0, Double.parseDouble(param.getDeaultValue()));

			param = cmd.getParameter("p_string2");
			Assert.assertEquals("5", param.getDeaultValue());

		} catch (Exception e)
		{
			e.printStackTrace();
			fail("Parsing failed");
		}
	}

	/**
	 * make sure the command parameter is set if the iscommand is 1
	 */
	public void testCommandParameter()
	{
		try
		{
			ProgramBuilder.cache.remove("field");

			Program cmd = ProgramBuilder.getProgram("field");
			assertNotNull(cmd.getCommandParameter());
			Assert.assertEquals(cmd.getCommandParameter().getName(), "seq");
			ProgramBuilder.cache.remove("example");
			cmd = ProgramBuilder.getProgram("example");
			assertNull(cmd.getCommandParameter());
		} catch (Exception e)
		{
			e.printStackTrace();
			fail("Parsing failed");
		}
	}

	/**
	 * we can parse sub category properly. Not a good test case for xml file
	 * since EMBOSS is from acd.
	 */
	public void testCategory()
	{
		ProgramCategory pc = ProgramBuilder.getProgramCategory();
		pc = ProgramBuilder.getProgramCategory();
		ProgramCategory emboss = pc.getSubCategory("EMBOSS");
		assertNotNull(emboss);
		assertTrue(emboss.getSubCategories().size() > 1);
	}

	/**
	 * basic transform test case.
	 */
	public void testTransform()
	{
		try
		{
			TransformerFactory tf = TransformerFactory.newInstance();

			InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("net/bioteam/appweb/model/example.xml");
			StreamSource ss = new StreamSource(in);

			InputStream sin = Thread.currentThread().getContextClassLoader().getResourceAsStream("net/bioteam/appweb/model/program.xslt");
			StreamSource xsls = new StreamSource(sin);

			ByteArrayOutputStream out = new ByteArrayOutputStream();
			StreamResult sr = new StreamResult(out);

			Transformer transformer = tf.newTransformer(xsls);
			transformer.transform(ss, sr);
		} catch (Exception e)
		{
			e.printStackTrace();
			fail("Parsing failed");
		}
	}

	/**
	 * basic JAXB test case
	 * 
	 * @throws JAXBException
	 */
	public void testJAXB() throws JAXBException
	{
		InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("net/bioteam/appweb/model/temp.xml");
		JAXBContext jc = JAXBContext.newInstance("net.bioteam.appweb.model");
		Unmarshaller unmarshaller = jc.createUnmarshaller();
		// unmarshaller.setListener(new myUnmarshListener());
		unmarshaller.setEventHandler(new javax.xml.bind.helpers.DefaultValidationEventHandler());
		unmarshaller.setProperty("com.sun.xml.bind.ObjectFactory",new ObjectFactory());
		Object obj = unmarshaller.unmarshal(in);

		JAXBElement<Program> jcmd = (JAXBElement<Program>) obj;
		Program cmd = (Program) jcmd.getValue();
		Assert.assertEquals(2, cmd.getParameters().size());
	}
}

class myUnmarshListener extends Unmarshaller.Listener
{
	private static int depth = 0;

	@Override
	public void afterUnmarshal(Object target, Object parent)
	{
		// super.afterUnmarshal(target, parent);
		printSpace(false);

		if (parent != null)
		{
			System.out.println("AFTER: " + parent.getClass().getName() + "---" + target.getClass().getName());
		} else
		{
			System.out.println("AFTER: NULL---" + target.getClass().getName());
		}
	}

	@Override
	public void beforeUnmarshal(Object target, Object parent)
	{
		// super.beforeUnmarshal(target, parent);
		printSpace(true);

		if (parent != null)
		{
			System.out.println("BEFORE: " + parent.getClass().getName() + "---" + target.getClass().getName());
		} else
		{
			System.out.println("BEFORE: NULL---" + target.getClass().getName());
		}
	}

	public void printSpace(boolean increase)
	{
		if (increase)
		{
			depth += 2;
		} else
		{
			depth -= 2;
		}

		for (int i = 0; i < depth; i++)
		{
			System.out.print("-");
		}

		System.out.print(">");
	}
}
